package com.dq.mail.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dq.mail.entity.User;
import com.dq.mail.exception.CommonException;
import com.dq.mail.service.UserService;
import com.dq.mail.mapper.UserMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dq.mail.utils.JwtUtil;
import com.dq.mail.utils.RedisConstants;
import com.dq.mail.utils.SystemCommons;
import com.dq.mail.utils.ThreadUserHolder;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * (User)表服务实现类
 *
 * @author Dq
 * @since 2023-03-03 11:04:34
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    UserMapper userMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public String login(User userDto) {
        /**
         * 用户登录
         * 1. 判断用户参数是否合法
         * 2. 合法进行生成JWT令牌
         * 3. 存入Redis TODO 并且设置2个拦截器实现token刷新
         *  a. 把最后的对象转化为Map对象
         *  b. key=> user:login:jwtKey(id生成)     value=> userMap对象
         */
        if (StringUtils.isBlank(userDto.getUsername()) || StringUtils.isBlank(userDto.getPassword())) {
            CommonException.throwError("用户参数不匹配");
        }
        //MD5加密  用户密码+salt盐
        String password = DigestUtils.md5Hex(userDto.getPassword() + SystemCommons.md5Secret);
        userDto.setPassword(password);
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, userDto.getUsername()).eq(User::getPassword, userDto.getPassword());
        User user = userMapper.selectOne(queryWrapper);
        if (ObjectUtils.isEmpty(user)) {
            //如果为Null 则为注册
            CommonException.throwError("密码错误或此账户未被注册");
        }
        String token = JwtUtil.createToken(user.getId(), SystemCommons.jwtTtl);
        //user ->Map 对象 实现Hash存入
        Map<String, Object> userMap = BeanUtil.beanToMap(user, new HashMap<>(),
                CopyOptions.create()
                        .ignoreNullValue()
                        .setFieldValueEditor((key, value) -> value.toString()));

        stringRedisTemplate.opsForHash().putAll(RedisConstants.LOGIN_USER_KEY + token, userMap);
        //设置过期时间
        stringRedisTemplate.expire(RedisConstants.LOGIN_USER_KEY + token, RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES);
        return token;
    }

    /**
     * @param token 用户令牌
     * @return
     */
    @Override
    public User getUserInfoByToken(String token) {
        /**
         * 1. 判断token是否存在 如果不存在 抛出异常
         * 2. 如果存在并且Redis 通过则没有过期 返回ThreadLocal数据
         * 3. 失败则提示用户token过期
         */
        if (StringUtils.isBlank(token)){
            CommonException.throwError("用户状态已过期，请重新登录");
        }
        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries(RedisConstants.LOGIN_USER_KEY + token);
        if (ObjectUtils.isEmpty(entries)){
            return null;
        }else {
            return ThreadUserHolder.getUser();
        }
    }

    /**
     * 创建新用户
     *
     * @param username 用户名称
     * @param password 用户密码
     * @return
     */
    private User createUserWithUserName(String username, String password) {
        User user = new User();
        password  = DigestUtils.md5Hex(password + SystemCommons.md5Secret);
        user.setUsername(username).setPassword(password);
        baseMapper.insert(user);
        return user;
    }

    public static void main(String[] args) {
        String password = DigestUtils.md5Hex(123456L + SystemCommons.md5Secret);
        System.out.println(password);
    }
}